package com.lyncs.ods.security.component;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.lyncs.ods.common.web.RequestHolder;
import com.lyncs.ods.constant.LyncsOdsConstant;
import com.lyncs.ods.domain.AdminUserDetails;
import com.lyncs.ods.modules.user.model.UserAuthInfo;
import com.lyncs.ods.modules.user.model.UserInfo;
import com.lyncs.ods.modules.user.service.UserService;
import com.lyncs.ods.security.util.JwtTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * JWT登录授权过滤器
 *
 * @author alex
 * @date 2022/01/25
 */
@Slf4j
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private UserService userService;
    @Value("${spring.profiles.active}")
    private String env;

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws ServletException, IOException {
        RequestHolder.setData(LyncsOdsConstant.Header.REQUEST_TIME, LocalDateTime.now(ZoneOffset.of("+8")));
        RequestHolder.setData(LyncsOdsConstant.Header.REQUEST_ID, RandomUtil.randomString(8));
        //RequestHolder.setData(LyncsOdsConstant.Header.AUTH_PLATFORM, RequestHolder.getPlatform());
        RequestHolder.setData(LyncsOdsConstant.Header.LANGUAGE, request.getHeader(LyncsOdsConstant.Header.LANGUAGE));
        String authToken = resolveToken(request);
        if (StringUtils.isNotEmpty(authToken)) {
            String openId = jwtTokenUtil.getOpenIdFromToken(authToken);
            log.info("checking openId:{}", openId);
            if (openId != null && SecurityContextHolder.getContext().getAuthentication() == null) {
                UserDetails userDetails = userService.loadUserByOpenId(openId);
                if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                    UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                    authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    log.info("authenticated openId:{}", openId);
                    SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }
        }
        chain.doFilter(request, response);
    }

    private String getDebuggerToken() {
        UserInfo userInfo = new UserInfo().setId(1L).setStatus(LyncsOdsConstant.UserStatus.ENABLE.getKey());
        UserAuthInfo userAuthInfo = new UserAuthInfo().setUserId(1L).setAppId("wx5fbafb66272c83fa").setAuthType(LyncsOdsConstant.AuthPlatform.WECHAT_WEB_APP.getKey()).setOpenId("o2yzl6Pp1CAOcV_LwrV-u4lXZ4Z4");
        UserDetails userDetails = new AdminUserDetails(userInfo, userAuthInfo);
        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        RequestHolder.saveCookie(LyncsOdsConstant.Header.COOKIE_PC, "7");
        return jwtTokenUtil.generateToken(userDetails);
    }

    /**
     * 解析token逻辑
     *
     * @param request
     * @return
     */
    private static String resolveToken(HttpServletRequest request) {
        //参考go的实现， 先从Token获取 再获取token，获取不到，则从cookie的_pt获取
        String cookie = request.getHeader(LyncsOdsConstant.Header.COOKIE);
        if (StringUtils.isEmpty(cookie)) {
            return null;
        }
        RequestHolder.setData(LyncsOdsConstant.Header.COOKIE, cookie);

        HashMap<String, String> cookieMap = Arrays.stream(cookie.split(LyncsOdsConstant.Common.SEMICOLON))
                .filter(StringUtils::isNotBlank)
                .map(item -> Map.of(item.split(LyncsOdsConstant.Common.COLON)[0], item.split(LyncsOdsConstant.Common.COLON)[1]))
                .collect(HashMap::new, HashMap::putAll, HashMap::putAll);
        cookieMap.forEach(RequestHolder::setData);
        return RequestHolder.getToken();
    }
}
